use crate::*;

pub fn memory_process(idx: usize, cmd: CmdMemory, session: &mut Session, ui_io: &UiIo) -> bool {
    let mut core = session.core(0).unwrap();

    let memory_param_rc = ui_io.get_memory_param();
    if idx >= memory_param_rc.row_count() {
        return false;
    }
    let memory_param = memory_param_rc.row_data(idx);
    let mut memory_param = if let Some(m_param) = memory_param {
        m_param
    } else {
        return false;
    };

    let addr_str = memory_param.address.to_string();
    let offset_str = memory_param.offset.to_string();
    let len_str = memory_param.length.to_string();

    let mut addr = if let Some(num) = utils::parse_number_str(&addr_str) {
        num as u64
    } else {
        ui_io.set_help_tip("address can't parse".into());
        return false;
    };

    if let Some(mut num) = utils::parse_number_str(&offset_str) {
        if num < 0 {
            num = -num;
            addr -= num as u64;
        } else {
            addr += num as u64;
        }
    }

    let len = if let Some(mut num) = utils::parse_number_str(&len_str) {
        if num < 0 {
            num = -num;
            addr -= num as u64;
        }
        num as usize
    } else {
        ui_io.set_help_tip("length can't parse".into());
        return false;
    };

    let mut result = true;
    let mut memory_str = String::new();
    match cmd {
        CmdMemory::ReadU8 => {
            let mut buff = vec![0xDD_u8; len];
            if let Err(e) = core.read_8(addr, &mut buff) {
                ui_io.set_help_tip(format!("core read_8 ERR: {:?}", e).into());
                result = false;
            }
            for (offset, byte) in buff.iter().enumerate() {
                if offset % 16 == 0 {
                    memory_str.push_str(&format!("{:08x}: ", addr + offset as u64));
                }
                memory_str.push_str(&format!("{:02x} ", byte));
                if (offset + 1) % 16 == 0 {
                    memory_str.push('\n');
                }
            }
        }
        CmdMemory::ReadU16 => {
            let mut buff = vec![0xDEAD_u16; len / 2];
            if let Err(e) = core.read_16(addr, &mut buff) {
                ui_io.set_help_tip(format!("core read_16 ERR: {:?}", e).into());
                result = false;
            }
            for (offset, word) in buff.iter().enumerate() {
                if offset % 8 == 0 {
                    memory_str.push_str(&format!("{:08x}: ", addr + (offset * 2) as u64));
                }
                memory_str.push_str(&format!("{:04x} ", word));
                if (offset + 1) % 8 == 0 {
                    memory_str.push('\n');
                }
            }
        }
        CmdMemory::ReadU32 => {
            let mut buff = vec![0xDEADBEEF_u32; len / 4];
            if let Err(e) = core.read_32(addr, &mut buff) {
                ui_io.set_help_tip(format!("core read_32 ERR: {:?}", e).into());
                result = false;
            }
            for (offset, word) in buff.iter().enumerate() {
                if offset % 4 == 0 {
                    memory_str.push_str(&format!("{:08x}: ", addr + (offset * 4) as u64));
                }
                memory_str.push_str(&format!("{:08x} ", word));
                if (offset + 1) % 4 == 0 {
                    memory_str.push('\n');
                }
            }
        }
    }
    if len % 16 == 0 {
        memory_str.push_str(&format!("{:08x}", addr + len as u64));
    }

    memory_param.data = memory_str.into();
    memory_param_rc.set_row_data(idx, memory_param);

    return result;
}
